'''
Created on 2011-6-6

@author: elm
'''
from ddbms.Schema import *
from ddbms.DdbmsException import *
from ddbms.Json import read,dump
from ddbms.URIUtil import parseConn,parseUri
import xmlrpclib
class TrackerSite(object):
    '''
    a site class for a tracker server
    '''
    schema = None
    site = None
    _tableId = 1
    _columnId = 1
    _siteId = 1
    _segmentId = 1
    conns = {}
    
    def tableId(self):
        id = self._tableId
        self._tableId += 1
        return id
    
    def columnId(self):
        id = self._columnId
        self._columnId += 1
        return id
    
    def siteId(self):
        id = self._siteId
        self._siteId += 1
        return id
    
    def segmentId(self):
        id = self._segmentId
        self._segmentId += 1
        return id
    
    def __init__(self):
        '''
        Constructor
        '''
        self.schema = Schema()
        self.site = []
        
    
    def join(self,uri,schema,json = False):
        '''
        RPC METHOD
        merge schema and global schema
        '''        
        if schema != None and isinstance(schema,str):
            schema = read(schema)
            json = True
        siteId = self.siteId()
        site = Site()
        site.id = siteId
        site.connection = uri
        site.segments = []
        self.schema.sites[site.id] = site
        if schema == None:
            self.reallocate(site)
            self.schema.siteId = siteId            
            if json:
                return dump(self.schema)
            else:
                return self.schema        
        colMap = {0:0}
        for rtid in schema.tables:            
            table = schema.tables[rtid]
            if table==None:
                continue
            tableId = self.tableId()
            t = Table()
            t.id = tableId
            t.name = table.name
            t.primaryKey = table.primaryKey
            t.segmentation = table.segmentation
            t.columns = []
            t.segments = []
            for rcid in table.columns:
                column = schema.columns[rcid]
                if column == None:
                    continue
                colId = self.columnId()
                col = Column()
                col.id = colId
                col.length = column.length
                col.name = column.name
                col.type = column.type
                col.table = tableId
                self.schema.columns[col.id] = col
                colMap[column.id] = col.id
                t.columns.append(col.id)
            if t.segmentation == Segment.Horizontal:
                for rsid in table.segments:
                    segment = schema.segments[rsid]
                    if segment == None:
                        continue
                    segId = self.segmentId()
                    seg = HorizontalSegment()
                    seg.id = segId
                    seg.columns = t.columns
                    seg.sites = [site.id]
                    seg.table = t.id
                    seg.name = segment.name
                    seg.segmentCondition = segment.segmentCondition
                    self.schema.segments[segId] = seg
                    site.segments.append(segId)
                    t.segments.append(segId)
            elif t.segmentation == Segment.Vertical:
                for rsid in table.segments:
                    segment = schema.segments[rsid]
                    if segment == None:
                        continue
                    segId = self.segmentId()
                    seg = VerticalSegment()
                    seg.id = segId                    
                    seg.sites = [site.id]
                    seg.table = t.id
                    seg.name = segment.name
                    seg.columns = []
                    for rcid in segment.columns:
                        seg.columns.append(colMap[rcid])
                    self.schema.segments[seg.id] = seg
                    site.segments.append(segId)
                    t.segments.append(seg.id)
            else:
                raise InvalidSegmentation
            self.schema.tables[t.id] = t
        self.reallocate(site)
        self.schema.siteId = siteId
        if json:
            return dump(self.schema)
        else:
            return self.schema    
    
    def reallocate(self,newsite):
        '''
        after new site is joined, 
        reallocate all segments
        '''
        #TODO: Fill TrackerSite.reallocate
        sites = len(self.schema.sites)
        segs = len(self.schema.segments)
        n = 1.5*segs/sites - len(newsite.segments)
        while n > 0: 
            min = 999999999
            minSeg = None
            for segId in self.schema.segments:
                seg = self.schema.segments[segId]
                if len(seg.sites)<min:
                    min = len(seg.sites)
                    minSeg = seg
            'Put minSeg to new site'
            newsite.segments += [minSeg.id]
            minSeg.sites += [newsite.id]
            n -= 1
        for siteId in self.schema.sites:
            site = self.schema.sites[siteId]
            if siteId!=newsite.id:
                if not siteId in self.conns:
                    self.conns[siteId] = xmlrpclib.ServerProxy(parseConn(site.connection),allow_none = 1)
                conn = self.conns[siteId]
                self.schema.siteId = siteId
                conn.notifySchemaChanged(dump(self.schema))
        print("[Tracker Server] Schema Changed:%s"%str(self.schema))
        